import os
import json
import time
import pandas as pd
from openai import OpenAI

# 初始化OpenAI客户端
client = OpenAI(
    base_url="https://ark.cn-beijing.volces.com/api/v3",
    api_key="330f54b7-915b-48a9-9599-c5e47c118cb5"  # 建议改为环境变量读取：os.getenv("ARK_API_KEY")
)


def get_reasons_with_prob(question: str) -> dict:
    """调用API获取问题的原因及概率"""
    system_prompt = """
    你是拓竹科技3D打印领域的专家，需完成以下任务：
    1. 分析用户提出的3D打印问题，列出该问题出现的所有可能原因；
    2. 为每个原因分配合理概率，所有原因的概率之和必须为100%（概率需带百分号）；
    3. 严格按照以下JSON格式输出结果（仅保留这两个字段，禁止添加其他字段）：
    {
        "用户问题": "用户的原始问题",
        "原因及概率": [
            {"原因": "具体原因描述", "概率": "XX%"}
        ]
    }
    注意：无需判断解决办法是否唯一，仅输出上述两个字段即可！
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": question}
            ]
        )

        response_content = response.choices[0].message.content.strip()
        if response_content.startswith('[') and response_content.endswith(']'):
            result = json.loads(response_content)[0]
        else:
            result = json.loads(response_content)

        if "用户问题" not in result or "原因及概率" not in result:
            raise KeyError("API返回缺少必要字段")
        if not isinstance(result["原因及概率"], list) or len(result["原因及概率"]) == 0:
            raise ValueError("原因及概率列表为空或格式错误")

        return result

    except json.JSONDecodeError:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": "API返回格式错误，无法解析", "概率": "100%"}]
        }
    except Exception as e:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": f"获取原因失败：{str(e)}", "概率": "100%"}]
        }


def judge_uniqueness_by_code(reasons: list) -> str:
    """纯代码逻辑判断解决办法是否唯一"""
    if len(reasons) == 1:
        return "是"
    for reason in reasons:
        try:
            prob = int(reason["概率"].strip('%'))
            if prob > 90:
                return "是"
        except (ValueError, KeyError):
            return "否"
    return "否"


def process_single_case(original_question: str) -> dict:
    """处理单个不唯一案例，生成补充信息后的结果"""
    system_prompt = """
    你是拓竹科技3D打印领域的问题补充专家，需按照以下要求处理用户问题：

    一、背景：拓竹科技3D打印用户提出问题。

    二、信息补充判断标准：
    1. 需补充打印机型号：当问题涉及机型专属功能、结构相关故障或软件适配，且未明确机型时。
    2. 需补充耗材信息：当问题涉及材料特性故障、适配限制或耗材状态相关问题，且未明确耗材时。
    3. 需补充打印参数：当问题涉及打印质量问题，且未明确参数时。
    4. 无需补充：问题给出机型、耗材及打印参数，或问题为询问通用操作流程。

    三、处理步骤：
    1. 判定补充需求：基于上述判断标准，识别需补充的信息类型。
    2. 补充信息：优先选择实际3D打印场景中概率最高的组合或者与用户问题最相关的信息。
    3. 以用户口吻将补充信息融入问题中，保留原始内容和核心意图。
    4. 输出修正后问题。

    四、约束要求：
    1. 机型库：H2S、H2D、H2D PRO、X1C、P1S、P1P、P2S、A1、A1 Mini。
    2. 耗材库：PLA、PETG、TPU、ABS、ASA、PC、ABS GF、PA6 GF、PA6 CF、ASA CF、PAHT CF 碳纤耗材、PET-CF、PPA-CF、PPS-CF。

    五、输出格式要求（严格按照此JSON格式输出）：
    {
        "原始用户问题": "用户的原始问题内容",
        "补充需求分析": "详细说明需要补充的信息类型及判断依据",
        "补充信息选择": {
            "机型": "选择的机型及选择理由（若无需补充则填无）",
            "耗材": "选择的耗材及选择理由（若无需补充则填无）",
            "打印参数": "选择的打印参数及选择理由（若无需补充则填无）"
        },
        "修正后问题": "融入补充信息后的用户问题"
    }
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": f"请处理用户问题：{original_question}"}
            ]
        )

        response_content = response.choices[0].message.content.strip()
        processed_result = json.loads(response_content)

        required_fields = ["原始用户问题", "补充需求分析", "补充信息选择", "修正后问题"]
        for field in required_fields:
            if field not in processed_result:
                raise KeyError(f"缺少必要字段：{field}")

        if not isinstance(processed_result["补充信息选择"], dict):
            raise ValueError("补充信息选择字段格式错误")
        info_fields = ["机型", "耗材", "打印参数"]
        for field in info_fields:
            if field not in processed_result["补充信息选择"]:
                processed_result["补充信息选择"][field] = "无"

        return processed_result

    except Exception as e:
        return {
            "原始用户问题": original_question,
            "补充需求分析": f"处理失败：{str(e)}",
            "补充信息选择": {"机型": "无", "耗材": "无", "打印参数": "无"},
            "修正后问题": original_question
        }


def generate_solution(question: str) -> dict:
    """为唯一问题生成解决方案"""
    system_prompt = """
    你是拓竹科技3D打印领域的专家，为用户问题提供准确解决方案。
    请直接给出清晰、简洁的解决步骤，不需要额外解释。
    输出格式：{"解决方案": "具体解决步骤，分点说明"}
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": question}
            ]
        )

        response_content = response.choices[0].message.content.strip()
        return json.loads(response_content)
    except Exception as e:
        return {"解决方案": f"生成解决方案失败：{str(e)}"}


def generate_graded_solutions(question: str) -> dict:
    """为不唯一问题生成按难易程度排序的解决方案"""
    system_prompt = """
    背景：拓竹科技3D打印用户提出问题。
    目标：根据用户问题，根据用户实操的难易程度，按照容易到困难的次序列出可能的解决办法。
    步骤：
    1. 分析问题：识别问题现象，分析最常见且互斥的可能原因（例如：硬件、软件设置、材料问题或操作错误）。
    2. 列出解决办法：为每个原因分配一个独立、具体的解决办法，避免解决办法重叠（即一个解决办法只针对一个原因）。
    3. 输出解决办法：按照用户实操的难易程度按照容易（仅包含简单几个操作步骤）到困难（需要进行复杂操作和多轮调试）的次序列出可能的解决办法。

    请严格按照以下JSON格式输出，将最后一个解决办法标记为"困难办法"，其余标记为"尝试办法"：
    {
        "问题": "用户问题内容",
        "解决办法": [
            {"类型": "尝试办法", "原因": "问题原因", "步骤": "具体解决步骤"},
            {"类型": "尝试办法", "原因": "问题原因", "步骤": "具体解决步骤"},
            {"类型": "困难办法", "原因": "问题原因", "步骤": "具体解决步骤"}
        ]
    }

    参考案例：
    {
        "问题": "我的P1S打印机用PETG耗材打印时出现严重拉丝，该如何处理？",
        "解决办法": [
            {"类型": "尝试办法", "原因": "回抽设置不当", "步骤": "1. 增加回抽距离至4-6mm；2. 提高回抽速度至40-50mm/s"},
            {"类型": "尝试办法", "原因": "喷嘴温度过高", "步骤": "1. 降低喷嘴温度5-10℃；2. 重新切片打印测试效果"},
            {"类型": "困难办法", "原因": "喷嘴磨损或堵塞", "步骤": "1. 关闭打印机电源并等待冷却；2. 拆卸喷嘴进行清洁或更换；3. 重新安装并校准喷嘴高度；4. 测试打印效果"}
        ]
    }
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": question}
            ]
        )

        response_content = response.choices[0].message.content.strip()
        return json.loads(response_content)
    except Exception as e:
        return {
            "问题": question,
            "解决办法": [{"类型": "错误", "原因": "生成解决方案失败", "步骤": str(e)}]
        }


def process_questions_from_excel(excel_path: str, question_column: str = "问题") -> list:
    """处理Excel中的问题，执行完整流程并返回结果"""
    try:
        # 读取Excel文件
        df = pd.read_excel(excel_path)
        if question_column not in df.columns:
            raise ValueError(f"Excel中未找到列名'{question_column}'")

        questions = df[question_column].dropna().astype(str).tolist()
        total_questions = len(questions)
        print(f"共检测到{total_questions}个有效问题，开始处理...\n")

        total_start_time = time.time()
        final_results = []

        for idx, question in enumerate(questions, 1):
            start_time = time.time()
            print(f"正在处理第{idx}/{total_questions}个问题：{question}")

            # 第一步：判断原始问题唯一性
            reason_data = get_reasons_with_prob(question)
            reasons = reason_data["原因及概率"]
            is_unique = judge_uniqueness_by_code(reasons)

            processing_result = {
                "序号": idx,
                "原始问题": question,
                "处理阶段": "",
                "结果": {}
            }

            if is_unique == "是":
                # 解决办法唯一，直接生成答案
                solution = generate_solution(question)
                processing_result["处理阶段"] = "直接生成解决方案（原始问题唯一）"
                processing_result["结果"] = solution
            else:
                # 解决办法不唯一，进行信息补充
                supplement_result = process_single_case(question)
                revised_question = supplement_result["修正后问题"]

                # 对补充后的问题再次判断唯一性
                revised_reason_data = get_reasons_with_prob(revised_question)
                revised_reasons = revised_reason_data["原因及概率"]
                revised_is_unique = judge_uniqueness_by_code(revised_reasons)

                if revised_is_unique == "是":
                    # 补充后问题唯一，生成答案
                    solution = generate_solution(revised_question)
                    processing_result["处理阶段"] = "补充信息后生成解决方案（补充后问题唯一）"
                    processing_result["补充信息"] = supplement_result
                    processing_result["结果"] = solution
                else:
                    # 补充后问题仍不唯一，生成分级解决方案
                    graded_solutions = generate_graded_solutions(revised_question)
                    processing_result["处理阶段"] = "生成分级解决方案（补充后问题仍不唯一）"
                    processing_result["补充信息"] = supplement_result
                    processing_result["结果"] = graded_solutions

            final_results.append(processing_result)

            elapsed_time = round(time.time() - start_time, 2)
            print(f"第{idx}个问题处理完成，耗时：{elapsed_time}秒\n")

        total_elapsed = round(time.time() - total_start_time, 2)
        print(f"所有问题处理完成！总耗时：{total_elapsed}秒\n")

        return final_results

    except Exception as e:
        print(f"处理过程出错：{str(e)}")
        return [{"错误": str(e)}]


if __name__ == "__main__":
    # 配置文件路径（请根据实际路径修改）
    excel_path = r"E:\pyPro\pythonProject1\TuiZhu\data\dialog.xlsx"
    output_json_path = "完整处理结果.json"

    # 处理所有问题
    results = process_questions_from_excel(excel_path)

    # 保存结果
    with open(output_json_path, "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=2)

    print(f"结果已保存至：{output_json_path}")

    # 打印第一个结果示例
    if results and "错误" not in results[0]:
        print("\n=== 处理结果示例（第一个案例）===")
        print(json.dumps(results[0], ensure_ascii=False, indent=2))